
#include <cstdio>
#include <BEvent>
#include <BKeyEvent>
#include <BEvent>
#include <BEvent>
#include <BMouseEvent>
#include <BEvent>
#include <BEvent>
#include <BTextEdit>
#include <BPainter>
#include <BCursor>
#include <BDrag>
#include <BSystem>
#include <BScreen>
#include "member_BWidget.h"
#include "member_BEvent.h"
#include "IWindow.h"
#include "IGlobal.h"

using namespace BWE;

#ifdef linux

#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysymdef.h>

extern Display *app_display;

bool IWindow::create()
{
	display = app_display;
	screen_number = DefaultScreen(app_display);
	screen = XScreenOfDisplay(display, screen_number);
	context = 0;

	BRect rect = boss->rect();
	int x = rect.x();
	int y = rect.y();
	int width = rect.width();
	int height = rect.height();

	int attribList[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None}; //{GLX_RGBA, GLX_DOUBLEBUFFER, None};
	XVisualInfo *vinfo = glXChooseVisual(display, 0, attribList);
	if (vinfo == 0)
	{
		XCloseDisplay(display);
		display = 0;
		perror("NO RGBA visual with double buffer");
		return false;
	}

	IWindow *firstWindow = app_windows.first();
	if (firstWindow)
		context = glXCreateContext(display, vinfo, firstWindow->context, GL_TRUE);
	else
		context = glXCreateContext(display, vinfo, None, GL_TRUE);
	if (context == 0)
	{
		XCloseDisplay(display);
		display = 0;
		perror("could not create rendering context");
		return false;
	}

	root = DefaultRootWindow(display);

	XSetWindowAttributes attribs;
	memset(&attribs, 0, sizeof(attribs));
	attribs.colormap = XCreateColormap(display, root, vinfo->visual, AllocNone);
	attribs.event_mask = CreateNotify | DestroyNotify | ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | StructureNotifyMask | SubstructureNotifyMask | SubstructureRedirectMask | OwnerGrabButtonMask | SelectionClear | SelectionRequest | SelectionNotify;

	unsigned long attrs_mask = CWBackPixel | CWBackPixmap | CWBorderPixel | CWBorderPixmap | CWColormap | CWEventMask | CWOverrideRedirect;

	hwnd = XCreateWindow(display, root, x, y, width, height, 0, vinfo->depth, InputOutput, vinfo->visual, attrs_mask, &attribs);
	XStoreName(display, hwnd, boss->title().cstr());
	XSetIconName(display, hwnd, "BWindow");

	wmDeleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", True);
	XSetWMProtocols(display, hwnd, &wmDeleteWindow, 1);

	setFrameless(widget_member(boss)->frameless);

	memset(fontCursors, 0, sizeof(fontCursors));
	return true;
}
bool IWindow::destroy()
{
	for (int i = 0; i < 160; i++)
	{
		if (fontCursors[i])
			XFreeCursor(display, fontCursors[i]);
	}
	if (context)
		glXDestroyContext(display, context);
	if (hwnd)
		XDestroyWindow(display, hwnd);
	if (display)
		XCloseDisplay(display);
	display = 0;
	hwnd = 0;
	context = 0;
	return true;
}

bool IWindow::makeCurrent(bool yes)
{
	if (display)
	{
		if (yes)
		{
			glXMakeCurrent(display, hwnd, context);
		}
		else
		{
			glXMakeCurrent(display, 0, 0);
		}
	}
	return true;
}
bool IWindow::swapBuffers()
{
	if (display)
	{
		glXSwapBuffers(display, hwnd);
		XFlush(display);
	}
	return true;
}

bool IWindow::setWindowTitle(const BString &title)
{
	puts(title.cstr());
	Atom wm_name = XInternAtom(display, "_NET_WM_NAME", False);
	Atom utf8_string = XInternAtom(display, "UTF8_STRING", False);
	if(wm_name != None && utf8_string != None)
	{
		XChangeProperty(display, hwnd, wm_name, utf8_string, 8, PropModeReplace, (BByte*)title.cstr(), title.size());
		return true;
	}
	int ret = XStoreName(display, hwnd, title.cstr());
	return ret == 0;
}
BString IWindow::getWindowTitle()
{
	BString title;
	Atom type = 0;
	int format = 0;
	unsigned long count = 0;
	unsigned long after = 0;
	BByte* data = 0;
	Atom prop = XInternAtom(app_display, "WM_NAME", False);
	if (Success == XGetWindowProperty(app_display, hwnd, prop, 0, 1024, False, XA_STRING, &type, &format, &count, &after, &data))
	{
		if (type == XA_STRING && format == 8 && count > 0)
		{
			title = (const char*)data;
		}
	}
	return title;
}

bool IWindow::setWindowIcon(const BIcon *icon)
{
	return false;
}
void IWindow::setFrameless(bool frameless)
{
	struct
	{
		unsigned long flag = 2;
		unsigned long functions = 0;
		unsigned long decorations = 1;
		long imput_mode = 0;
		unsigned long status = 0;
	} hints;
	if (frameless)
		hints.decorations = 0;
	Atom property = XInternAtom(display, "_MOTIF_WM_HINTS", False);
	XChangeProperty(display, hwnd, property, property, 32, PropModeReplace, (unsigned char *)&hints, sizeof(hints) / sizeof(long));
}

bool IWindow::setWindowPos(const BPoint &pos)
{
	if (hwnd)
	{
		if (pos != this->getWindowPos())
		{
			XMoveWindow(display, hwnd, pos.x(), pos.y());
			BPoint retpos = this->getWindowPos();
			return true;
		}
	}
	return false;
}
BPoint IWindow::getWindowPos()
{
	XWindowAttributes attribs;
	int ret = XGetWindowAttributes(display, hwnd, &attribs);
	return BPoint(attribs.x, attribs.y);
}

bool IWindow::setWindowSize(const BSize &size)
{
	if (hwnd)
	{
		if (size != this->getWindowSize())
		{
			resized = true;
			XResizeWindow(display, hwnd, size.width(), size.height());
			return true;
		}
	}
	return false;
}
BSize IWindow::getWindowSize()
{
	XWindowAttributes attribs;
	int ret = XGetWindowAttributes(display, hwnd, &attribs);
	return BSize(attribs.width, attribs.height);
}

void IWindow::setInputPoint(const BPoint &point)
{
}
BPoint IWindow::getInputPoint() const
{
	return BPoint();
}

bool IWindow::isMaximized()
{
	return normalRect.valid();
}
bool IWindow::isMinimized()
{
	XWindowAttributes attribs;
	XGetWindowAttributes(display, hwnd, &attribs);
	return attribs.map_state == IsUnmapped;
}

void IWindow::showNormal()
{
	XWindowAttributes attribs;
	XGetWindowAttributes(display, hwnd, &attribs);
	if (attribs.map_state == IsUnmapped)
	{
		XMapWindow(display, hwnd);
	}
	Atom wm_state = XInternAtom(display, "_NET_WM_STATE", False);
	Atom fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
	Atom type = 0;
	int format = 0;
	unsigned long count, after;
	Atom* states = NULL;
	XGetWindowProperty(display, hwnd, wm_state, 0, 1024, False, XA_ATOM, &type, &format, &count, &after, (BByte**)&states);
	if (states && count > 0)
	{
		bool is_fullscreen = false;
		for (int i = 0; i < count; i++)
		{
			if (states[i] == fullscreen)
				is_fullscreen = true;
		}
		XFree(states);
		if (is_fullscreen)
		{
			XClientMessageEvent event;
			event.type = ClientMessage;
			event.window = hwnd;
			event.message_type = wm_state;
			event.format = 32;
			event.data.l[0] = 0;
			event.data.l[1] = fullscreen;
			event.data.l[2] = 0;
			event.data.l[3] = 0;
			event.data.l[4] = 0;
			XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&event);
			XFlush(display);
			usleep(100000);
		}
	}
	if (normalRect.valid())
	{
		XMoveResizeWindow(display, hwnd, normalRect.x(), normalRect.y(), normalRect.width(), normalRect.height());
		normalRect.reset();
	}
}
void IWindow::showMaximized()
{
	puts("show-maximized");
	normalRect = boss->rect();
	int fullWidth = XWidthOfScreen(screen);
	int fullHeight = XHeightOfScreen(screen);
	int ret = XMoveResizeWindow(display, hwnd, 0, 0, fullWidth, fullHeight);
}
void IWindow::showMinimized()
{
	int ret = XIconifyWindow(display, hwnd, screen_number);
}
void IWindow::showFullScreen()
{
	normalRect = boss->rect();
	int fullWidth = XWidthOfScreen(screen);
	int fullHeight = XHeightOfScreen(screen);
	int ret = XMoveResizeWindow(display, hwnd, 0, 0, fullWidth, fullHeight);
}
void IWindow::hideWindow()
{
	int ret = XUnmapWindow(display, hwnd);
}

void IWindow::freshCursor()
{
	BImage *image = 0;
	CursorType type = Cursor_None;
	if (hoverCursor)
	{
		type = hoverCursor->type();
		image = hoverCursor->image(type);
	}
	if (image)
	{
		XUndefineCursor(display, hwnd);
		return;
	}
	if (hoverCursor)
		type = hoverCursor->type();
	unsigned int font_cursor_type = 0;
	switch (type)
	{
	case Cursor_None:
	case Cursor_Arrow:
		font_cursor_type = XC_arrow;
		break;
	case Cursor_Ibeam:
		font_cursor_type = XC_xterm;
		break;
	case Cursor_Cross:
		font_cursor_type = XC_X_cursor;
		break;
	case Cursor_Wait:
		font_cursor_type = XC_watch;
		break;
	case Cursor_Forbidden:
		font_cursor_type = XC_X_cursor;
		break;
	case Cursor_Hand:
		font_cursor_type = XC_hand2;
		break;
	case Cursor_Help:
		font_cursor_type = XC_question_arrow;
		break;
	case Cursor_UpArrow:
		font_cursor_type = XC_sb_up_arrow;
		break;
	case Cursor_SizeTop:
		font_cursor_type = XC_top_side;
		break;
	case Cursor_SizeLeft:
		font_cursor_type = XC_left_side;
		break;
	case Cursor_SizeRight:
		font_cursor_type = XC_right_side;
		break;
	case Cursor_SizeBottom:
		font_cursor_type = XC_bottom_side;
		break;
	case Cursor_SizeVer:
		font_cursor_type = XC_sb_v_double_arrow;
		break;
	case Cursor_SizeHor:
		font_cursor_type = XC_sb_h_double_arrow;
		break;
	case Cursor_SizeLeftTop:
		font_cursor_type = XC_top_left_corner;
		break;
	case Cursor_SizeRightBottom:
		font_cursor_type = XC_bottom_right_corner;
		break;
	case Cursor_SizeLeftBottom:
		font_cursor_type = XC_bottom_left_corner;
		break;
	case Cursor_SizeRightTop:
		font_cursor_type = XC_top_right_corner;
		break;
	case Cursor_SizeAll:
		font_cursor_type = XC_fleur;
		break;
	default:
		break;
	}
	if (fontCursors[font_cursor_type] == 0)
	{
		fontCursors[font_cursor_type] = XCreateFontCursor(display, font_cursor_type);
	}
	Cursor cursor = fontCursors[font_cursor_type];
	XDefineCursor(display, hwnd, cursor);
	XFlush(display);
}

bool IWindow::procEvent(const XEvent& event)
{
	switch (event.type)
	{
	case ReparentNotify:
	{
		const XReparentEvent &reparent = (const XReparentEvent &)event;
		break;
	}
	case CreateNotify:
	{
		const XCreateWindowEvent &createEvent = (const XCreateWindowEvent &)event;
		widget_member(boss)->syncWindowPos(BPoint(createEvent.x, createEvent.y));
		widget_member(boss)->syncWindowSize(BSize(createEvent.width, createEvent.height));
		break;
	}
	case DestroyNotify:
	{
		const XDestroyWindowEvent &destroyEvent = (const XDestroyWindowEvent &)event;
		BEvent closeEvent(Event_Close);
		widget_member(boss)->procEvent(closeEvent);
		break;
	}
	case ClientMessage:
	{
		if (event.xclient.data.l[0] == wmDeleteWindow)
		{
			BEvent closeEvent(Event_Close);
			widget_member(boss)->procEvent(closeEvent);
		}
		break;
	}
	case Expose:
	{
		refresh = true;
		break;
	}
	case ConfigureNotify:
	{
		resized = true;
		const XConfigureEvent &configEvent = (const XConfigureEvent &)event;
		widget_member(boss)->syncWindowPos(BPoint(configEvent.x, configEvent.y));
		widget_member(boss)->syncWindowSize(BSize(configEvent.width, configEvent.height));
		break;
	}
	case FocusIn:
	{
		focusing = true;
		BEvent focusEvent(Event_Focus);
		focusEvent.setValue(true);
		widget_member(boss)->procEvent(focusEvent);
		break;
	}
	case FocusOut:
	{
		focusing = false;
		BEvent focusEvent(Event_Focus);
		focusEvent.setValue(false);
		widget_member(boss)->procEvent(focusEvent);
		break;
	}
	case KeyPress:
	{
		XKeyEvent xkevent = (const XKeyEvent &)event;
		KeySym keysym = 0;
		char buf[8] = {0};
		int len = XLookupString(&xkevent, buf, sizeof(buf), &keysym, NULL);
		if (Key key = filterKey(keysym))
		{
			keyStates[key] = true;
			if (focusWidget)
			{
				bool ctrl = iscntrl(buf[0]);
				if (!ctrl && buf[len] == 0)
				{
					BCode code = buf;
					const char *ustr = code.str();
					BEvent event(Event_Input, code);
					widget_member(focusWidget)->procEvent(event);
				}
				BKeyEvent keyEvent(Event_KeyPress, key);
				event_member(&keyEvent)->window = this;
				widget_member(focusWidget)->procEvent(keyEvent);
				if (Key vkey = virtualKey(keysym))
				{
					keyEvent.setKey(vkey);
					keyStates[vkey] = true;
					widget_member(focusWidget)->procEvent(keyEvent);
				}
				if (keyEvent.accepted())
					break;
				this->procShortcut();
			}
		}
		break;
	}
	case KeyRelease:
	{
		XKeyEvent xkevent = (const XKeyEvent &)event;
		KeySym keysym = 0;
		char buf[8] = {0};
		int len = XLookupString(&xkevent, buf, sizeof(buf), &keysym, NULL);
		if (Key key = filterKey(keysym))
		{
			keyStates[key] = false;
			if (focusWidget)
			{
				BKeyEvent keyEvent(Event_KeyRelease, key);
				event_member(&keyEvent)->window = this;
				widget_member(focusWidget)->procEvent(keyEvent);
				if (Key vkey = virtualKey(keysym))
				{
					keyEvent.setKey(vkey);
					keyStates[vkey] = false;
					widget_member(focusWidget)->procEvent(keyEvent);
				}
			}
		}
		break;
	}
	case EnterNotify:
	{
		if (!mouse_pressed)
		{
			hoverWidget = boss;
			BMouseEvent mouseEvent(Event_MouseEnter);
			widget_member(boss)->procEvent(mouseEvent);
		}
		break;
	}
	case LeaveNotify:
	{
		if (!mouse_pressed)
		{
			if (hoverWidget)
			{
				BMouseEvent mouseEvent(Event_MouseLeave);
				widget_member(boss)->procEvent(mouseEvent);
				hoverWidget = 0;
			}
		}
		break;
	}
	case MotionNotify:
	{
		static Time time = 0;
		int posx = 0;
		int posy = 0;
		Time interval = (BReal)1 / app_frequency * 1000;
		const XMotionEvent &motionEvent = (const XMotionEvent &)event;
		if (motionEvent.time - time > interval && motionEvent.x != posx && motionEvent.y != posy)
		{
			BPoint absolutePos(motionEvent.x, motionEvent.y);
			BPoint globalPos(motionEvent.x_root, motionEvent.y_root);
			BMouseEvent mouseEvent(Event_MouseMove, mouse_button);
			mouseEvent.setAbsolutePos(absolutePos);
			mouseEvent.setGlobalPos(globalPos);
			this->procMouseMove(mouseEvent);
			time = motionEvent.time;
			posx = motionEvent.x;
			posy = motionEvent.y;
		}
		break;
	}
	case ButtonPress:
	{
		XSetInputFocus(display, hwnd, RevertToNone, CurrentTime);
		const XButtonEvent &buttonEvent = (const XButtonEvent &)event;
		BPoint absolutePos(buttonEvent.x, buttonEvent.y);
		BPoint globalPos(buttonEvent.x_root, buttonEvent.y_root);
		if (buttonEvent.button == Button4)
		{
			BMouseEvent mouseEvent(Event_MouseWheel, Button_Middle);
			mouseEvent.setGlobalPos(globalPos);
			mouseEvent.setAbsolutePos(absolutePos);
			mouseEvent.setWheel(1);
			this->procMouseWheel(mouseEvent);
		}
		else if (buttonEvent.button == Button5)
		{
			BMouseEvent mouseEvent(Event_MouseWheel, Button_Middle);
			mouseEvent.setGlobalPos(globalPos);
			mouseEvent.setAbsolutePos(absolutePos);
			mouseEvent.setWheel(-1);
			this->procMouseWheel(mouseEvent);
		}
		else
		{
			Button button = Button_None;
			if (buttonEvent.button == Button1)
				button = Button_Left;
			if (buttonEvent.button == Button2)
				button = Button_Middle;
			if (buttonEvent.button == Button3)
				button = Button_Right;
			BMouseEvent mouseEvent(Event_MousePress, button);
			mouseEvent.setAbsolutePos(absolutePos);
			mouseEvent.setGlobalPos(globalPos);
			this->procMousePress(mouseEvent);
		}
		break;
	}
	case ButtonRelease:
	{
		const XButtonEvent &buttonEvent = (const XButtonEvent &)event;
		BPoint absolutePos(buttonEvent.x, buttonEvent.y);
		BPoint globalPos(buttonEvent.x_root, buttonEvent.y_root);
		Button button = Button_None;
		if (buttonEvent.button == Button1)
			button = Button_Left;
		if (buttonEvent.button == Button2)
			button = Button_Middle;
		if (buttonEvent.button == Button3)
			button = Button_Right;
		BMouseEvent mouseEvent(Event_MouseRelease, button);
		mouseEvent.setAbsolutePos(absolutePos);
		mouseEvent.setGlobalPos(globalPos);
		this->procMouseRelease(mouseEvent);
		break;
	}
	case MapNotify:
	{
		const XMapEvent &mapEvent = (const XMapEvent &)event;
		break;
	}
	case UnmapNotify:
	{
		const XUnmapEvent &unmapEvent = (const XUnmapEvent &)event;
		break;
	}
	case SelectionClear:
	{
		const XSelectionClearEvent &clear = event.xselectionclear;
		app_clipBoard.clear();
		break;
	}
	case SelectionRequest:
	{
		const XSelectionRequestEvent &request = event.xselectionrequest;
		XSelectionEvent respond;
		respond.type = SelectionNotify;
		respond.display = request.display;
		respond.requestor = request.requestor;
		respond.selection = request.selection;
		respond.target = request.target;
		respond.property = 0;
		respond.time = request.time;

		Atom targets[] = {
			XInternAtom(app_display, "TARGETS", False),
			XInternAtom(app_display, "UTF8_STRING", False),
			XA_STRING
			};
		if (request.target == targets[0])
		{
			XChangeProperty(app_display, request.requestor, request.property,XA_ATOM, 32, PropModeReplace, (BByte*)targets, 3);
			respond.property = request.property;
		}
		else if (request.target == targets[1])
		{
			if (app_clipBoard.is<BString>())
			{
				const BString &text = app_clipBoard;
				XChangeProperty(app_display, request.requestor, request.property, request.target, 8, PropModeReplace, (BByte*)text.cstr(), text.size());
				respond.property = request.property;
			}
		}
		else if (request.target == XA_STRING)
		{
			if (app_clipBoard.is<BString>())
			{
				const BString& text = app_clipBoard;
				XChangeProperty(app_display, request.requestor, request.property, request.target, 8, PropModeReplace, (BByte*)text.cstr(), text.size());
				respond.property = request.property;
			}
		}
		XSendEvent(app_display, request.requestor, False, 0, (XEvent*)&respond);
		XFlush(app_display);
		break;
	}
	case SelectionNotify:
	{
		const XSelectionEvent& selection = event.xselection;
		if (selection.target == XA_STRING || selection.target == XInternAtom(app_display, "UTF8_STRING", False))
		{
			Atom type = 0;
			int format = 0;
			unsigned long nitems = 0;
			unsigned long bytes_after = 0;
			unsigned char *data = 0;
			Atom prop = selection.property;
			if (Success == XGetWindowProperty(app_display, hwnd, prop, 0, LONG_MAX, False, 0, &type, &format, &nitems, &bytes_after, &data))
			{
				app_clipBoard = new BString((const char*)data);
				XFree(data);
			}
		}
		break;
	}
	default:
		break;
	}
	return true;
}
Key IWindow::filterKey(KeySym keysym)
{
	switch (keysym)
	{
	case XK_0:
	case XK_KP_0:
		return Key_0;
	case XK_1:
	case XK_KP_1:
		return Key_1;
	case XK_2:
	case XK_KP_2:
		return Key_2;
	case XK_3:
	case XK_KP_3:
		return Key_3;
	case XK_4:
	case XK_KP_4:
		return Key_4;
	case XK_5:
	case XK_KP_5:
		return Key_5;
	case XK_6:
	case XK_KP_6:
		return Key_6;
	case XK_7:
	case XK_KP_7:
		return Key_7;
	case XK_8:
	case XK_KP_8:
		return Key_8;
	case XK_9:
	case XK_KP_9:
		return Key_9;

	case XK_F1:
	case XK_KP_F1:
		return Key_F1;
	case XK_F2:
	case XK_KP_F2:
		return Key_F2;
	case XK_F3:
	case XK_KP_F3:
		return Key_F3;
	case XK_F4:
	case XK_KP_F4:
		return Key_F4;

	case XK_F5:
		return Key_F5;
	case XK_F6:
		return Key_F6;
	case XK_F7:
		return Key_F7;
	case XK_F8:
		return Key_F8;
	case XK_F9:
		return Key_F9;
	case XK_F10:
		return Key_F10;
	case XK_F11:
		return Key_F11;
	case XK_F12:
		return Key_F12;

	case XK_space:
		return Key_Space;
	case XK_colon:
		return Key_Colon;
	case XK_semicolon:
		return Key_Semicolon;
	case XK_less:
		return Key_Less;
	case XK_equal:
		return Key_Equal;
	case XK_greater:
		return Key_Greater;
	case XK_question:
		return Key_Question;

	case XK_A:
		return Key_A;
	case XK_B:
		return Key_B;
	case XK_C:
		return Key_C;
	case XK_D:
		return Key_D;
	case XK_E:
		return Key_E;
	case XK_F:
		return Key_F;
	case XK_G:
		return Key_G;
	case XK_H:
		return Key_H;
	case XK_I:
		return Key_I;
	case XK_J:
		return Key_J;
	case XK_K:
		return Key_K;
	case XK_L:
		return Key_L;
	case XK_M:
		return Key_M;
	case XK_N:
		return Key_N;
	case XK_O:
		return Key_O;
	case XK_P:
		return Key_P;
	case XK_Q:
		return Key_Q;
	case XK_R:
		return Key_R;
	case XK_S:
		return Key_S;
	case XK_T:
		return Key_T;
	case XK_U:
		return Key_U;
	case XK_V:
		return Key_V;
	case XK_W:
		return Key_W;
	case XK_X:
		return Key_X;
	case XK_Y:
		return Key_Y;
	case XK_Z:
		return Key_Z;

	case XK_bracketleft:
		return Key_LBracket;
	case XK_backslash:
		return Key_Backslash;
	case XK_bracketright:
		return Key_RBracket;
	case XK_asciicircum:
		return Key_None;
	case XK_underscore:
		return Key_Underscore;
	case XK_grave:
		return Key_None;

	case XK_a:
		return Key_A;
	case XK_b:
		return Key_B;
	case XK_c:
		return Key_C;
	case XK_d:
		return Key_D;
	case XK_e:
		return Key_E;
	case XK_f:
		return Key_F;
	case XK_g:
		return Key_G;
	case XK_h:
		return Key_H;
	case XK_i:
		return Key_I;
	case XK_j:
		return Key_J;
	case XK_k:
		return Key_K;
	case XK_l:
		return Key_L;
	case XK_m:
		return Key_M;
	case XK_n:
		return Key_N;
	case XK_o:
		return Key_O;
	case XK_p:
		return Key_P;
	case XK_q:
		return Key_Q;
	case XK_r:
		return Key_R;
	case XK_s:
		return Key_S;
	case XK_t:
		return Key_T;
	case XK_u:
		return Key_U;
	case XK_v:
		return Key_V;
	case XK_w:
		return Key_W;
	case XK_x:
		return Key_X;
	case XK_y:
		return Key_Y;
	case XK_z:
		return Key_Z;

	case XK_BackSpace:
		return Key_Back;
	case XK_Tab:
		return Key_Tab;
	case XK_Return:
		return Key_Enter;
	case XK_Escape:
		return Key_Escape;
	case XK_Delete:
		return Key_Delete;

	case XK_Home:
	case XK_KP_Home:
		return Key_Home;
	case XK_Left:
	case XK_KP_Left:
		return Key_Left;
	case XK_Up:
	case XK_KP_Up:
		return Key_Up;
	case XK_Right:
	case XK_KP_Right:
		return Key_Right;
	case XK_Down:
	case XK_KP_Down:
		return Key_Down;
	case XK_Page_Up:
	case XK_KP_Page_Up:
		return Key_PageUp;
	case XK_Page_Down:
	case XK_KP_Page_Down:
		return Key_PageDown;
	case XK_End:
	case XK_KP_End:
		return Key_End;

	case XK_Shift_L:
		return Key_LShift;
	case XK_Shift_R:
		return Key_RShift;
	case XK_Control_L:
		return Key_LCtrl;
	case XK_Control_R:
		return Key_RCtrl;
	case XK_Alt_L:
		return Key_LAlt;
	case XK_Alt_R:
		return Key_RAlt;
	case XK_Num_Lock:
		return Key_NumLock;
	case XK_Caps_Lock:
		return Key_CapsLock;

	default:
		break;
	}
	return Key_None;
}
Key IWindow::virtualKey(KeySym keysym)
{
	switch (keysym)
	{
	case XK_Shift_L:
		return Key_Shift;
	case XK_Shift_R:
		return Key_Shift;

	case XK_Control_L:
		return Key_Ctrl;
	case XK_Control_R:
		return Key_Ctrl;

	case XK_Alt_L:
		return Key_Alt;
	case XK_Alt_R:
		return Key_Alt;

	default:
		break;
	}
	return Key_None;
}

#endif
